/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
* glutHeightMapDisplay.cpp
*
*/
#include "glutHeightMapDisplay.h"
#include "../ModelEditor/COpenGLCamera.h"


static int Window_ID1;
COpenGLCamera cam;  ///< All camera handling
CGLHeightMap *global_hmPtr=NULL;
ownThreadHandle glutthread;


void glutThread(){
	 int argc = 1;
	 char *argv[] = {"hohhoh"};
	 glutInit(&argc, argv);
	 glutInitWindowPosition(200, 200);
	 glutInitWindowSize(640, 480);
	 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH| GLUT_MULTISAMPLE);
	
	 Window_ID1=glutCreateWindow("3D-Heightmap Visualisator - Jari Saarinen (2007)");
	 glEnable(GL_DEPTH_TEST);

	 glutIgnoreKeyRepeat(1);
	 glutSpecialFunc(pressKey);
	 glutSpecialUpFunc(releaseKey);
		//glutKeyboardFunc(&Key);
	 glutKeyboardFunc(Key);
	 glutKeyboardUpFunc(KeyUp);
	 glutMouseFunc(glutMouse);  // called when the application receives a input from the mouse

	 glutDisplayFunc(renderScene);
	 glutIdleFunc(glutIdleFunc);
	 glutReshapeFunc(changeSize);	
		
//	 cam.setCameraPose(0, -12,-9, 0, 30);
//				void setCameraPose(float _x, float _y,float _z, float _yaw, float _pitch){
	 cam.setCameraPose(0, -2,0, 135, 30);
	 cam.setResolution(0.1, 1);
		glutMainLoop();
}

void glut_hm_initialize(int argc,char *argv[],CGLHeightMap *hmPtr){
		global_hmPtr = hmPtr;
		glutthread = ownThread_Create((void *)glutThread, NULL);
		//glutMainLoop();
		ownSleep_ms(1 * 500);
}

/**
* Renders something
**/
void setMaterialParameters(){
		float Light_Ambient[]=  { 0.1f, 0.1f, 0.1f, 1.0f };
		//float Light_Diffuse[]=  { 1.2f, 1.2f, 1.2f, 1.0f }; 
		float Light_Diffuse[]=  { .6f, .6f, .6f, 1.0f }; 
		float Light_Position[]= { 0.0f, 10.0f, 0.0f, 1.0f };
		float Light_Specular[]= { 5.0f, 5.0f, 5.0f, 10.0f };
		glutSetWindow(Window_ID1);
		
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glEnable(GL_LIGHTING);

		// Draw ground
		// A handy trick -- have surface material mirror the color.
		glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
		glEnable(GL_COLOR_MATERIAL);
		
		glLightfv(GL_LIGHT1, GL_POSITION, Light_Position);
		glLightfv(GL_LIGHT1, GL_AMBIENT,  Light_Ambient);
		glLightfv(GL_LIGHT1, GL_DIFFUSE,  Light_Diffuse); 
		glLightfv(GL_LIGHT1, GL_SPECULAR,  Light_Specular); 
		glEnable (GL_LIGHT1); 
		
		////////////////// Draw a BIG Floor ///////////////////////////
		float c[4];
		glGetFloatv(GL_CURRENT_COLOR,c);
		glEnable (GL_BLEND); 
		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glColor4f(0,1,1,0.1);
		glBegin(GL_QUADS);
		glVertex3f(-100,-1,100);
		glVertex3f(100,-1,100);
		glVertex3f(100,-1,-100);
		glVertex3f(-100,-1,-100);
		glEnd();
		glDisable (GL_BLEND); 
		glColor4f(c[0],c[1],c[2],c[3]);
		
}
////////////////////////////////////////////////////////////////////////
///////// GLUT CALLBACK FUNCTIONS
////////////////////////////////////////////////////////////////////////
 
//glut displayfunc
void renderScene(void) {
		setMaterialParameters();
		cam.updateCamera();
		if(global_hmPtr!=NULL) global_hmPtr->draw();
		glFlush();
		glutSwapBuffers();	
}
//glut idle func
void glutIdleFunc(void){
		glutPostRedisplay(); 
}
// Resize func
void changeSize(int w, int h) {
		cam.resizeFunc(w,h); 
}
//Special key down func  
void pressKey(int key, int xx, int yy) {
		cam.cameraKeyFunc(0,1,key);
}
// Special Key Up func
void releaseKey(int key, int xx, int yy) {
		cam.cameraKeyFunc(0,0,key);
}
// Key func
void Key(unsigned char key,int x, int y){
		cam.cameraKeyFunc(1,1,key);
}

void KeyUp(unsigned char key,int x, int y){
		cam.cameraKeyFunc(1,0,key);
}


//------------------------------------------------------------------------
// Function that handles mouse input
//------------------------------------------------------------------------
/*
* Calculates the transformation between mouse coordinate and object frame 
* Returns x and y (the scaled depth value is stored to V.z)
*/

CVector3 GetOGLPos(int x, int y)
{
		GLint viewport[4];
		GLdouble modelview[16];
		GLdouble projection[16];
		GLfloat winX, winY, winZ;
		GLdouble posX, posY, posZ;
		CVector3 V;

		glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
		glGetDoublev( GL_PROJECTION_MATRIX, projection );
		glGetIntegerv( GL_VIEWPORT, viewport );

		winX = (float)x;
		winY = (float)viewport[3] - (float)y;
	//winZ = z;

		glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
	//fprintf(stderr,"X:%d, Y:%d\t",x,y);
	//fprintf(stderr,"WIN::X:%.1f, Y:%.1f Z:%.4f\n",winX,winY,winZ);

		gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
		V.x = (float)posX;
		V.y = (float)posY;
		V.z = (float)posZ;
		return V;
}

void glutMouse(int button, int state, int x, int y)
{
		int object;
		CVector3 V;
		
		if(state == GLUT_DOWN){
				switch(button){
						case GLUT_LEFT_BUTTON:
						///Read the target mode
								float h;
								V = GetOGLPos(x,y); // The world coordinates x,y
								h = V.y;
								V.x = V.x +12.5;
								V.y = -V.z +12.5; 
								fprintf(stderr,"Mouse click on %.2f %.2f h=%.2f\n",V.x,V.y,h);
								break;
						case GLUT_RIGHT_BUTTON:
								break;
						default:
								break;
				}
		}else{ 
				if (state == GLUT_UP){
				}			
		}
		
}
